package com.example.demo.interceptor;


import com.example.demo.common.ResponseResult;
import com.example.demo.common.ResponseResultFactory;
import com.example.demo.exception.FieldException;
import com.example.demo.exception.LimitException;
import com.example.demo.exception.OtherException;
import com.example.demo.exception.UnauthorizedException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;

/**
 * @author lyc
 * @date 2019/4/23.
 *  参考
 * https://www.cnblogs.com/jurendage/p/11255197.html
 */
@ControllerAdvice
public class ExceptionsHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionsHandler.class);

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public ResponseResult methodArgumentNotValidException(MethodArgumentNotValidException exception) {
        StringBuilder sb = getStringBuilder(exception);
        return ResponseResultFactory.fieldFail(sb.toString());
    }

    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseBody
    public ResponseResult IllegalArgumentException(IllegalArgumentException exception) {
        return ResponseResultFactory.fieldFail(exception.getMessage());
    }

    @ExceptionHandler(LimitException.class)
    @ResponseBody
    public ResponseResult LimitException(LimitException exception) {
        return ResponseResultFactory.fieldFail(exception.getMessage());
    }
    private StringBuilder getStringBuilder(MethodArgumentNotValidException exception) {
        BindingResult br = exception.getBindingResult();
        List<FieldError> fieldErrors = br.getFieldErrors();
        StringBuilder sb = new StringBuilder();
        for (FieldError fieldError : fieldErrors) {
            if (sb.length() > 0) {
                sb.append("，");
            }
            sb.append(fieldError.getDefaultMessage());
        }
        return sb;
    }

    @ExceptionHandler(BindException.class)
    @ResponseBody
    public ResponseResult bindException(BindException exception) {
        BindingResult br = exception.getBindingResult();
        List<FieldError> fieldErrors = br.getFieldErrors();
        StringBuilder sb = new StringBuilder();
        for (FieldError fieldError : fieldErrors) {
            if (sb.length() > 0) {
                sb.append("，");
            }
            sb.append(fieldError.getDefaultMessage());
        }
        return ResponseResultFactory.fieldFail(sb.toString());
    }

    @ExceptionHandler(OtherException.class)
    @ResponseBody
    public ResponseResult otherException(OtherException exception) {
        LOGGER.error(ExceptionsHandler.class.getName(), exception);
        return ResponseResultFactory.other(2001, exception.getMessage());
    }

    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public ResponseResult constraintViolationException(ConstraintViolationException exception) {
        Set<ConstraintViolation<?>> constraintViolations = exception.getConstraintViolations();
        StringBuilder sb = new StringBuilder();
        for (ConstraintViolation<?> cv : constraintViolations) {
            if (sb.length() > 0) {
                sb.append("，");
            }
            sb.append(cv.getMessage());
        }
        return ResponseResultFactory.fieldFail(sb.toString());
    }

    @ExceptionHandler(FieldException.class)
    @ResponseBody
    public ResponseResult fieldException(FieldException exception) {
        LOGGER.error(ExceptionsHandler.class.getName(), exception);
        return ResponseResultFactory.fieldFail(exception.getMessage());
    }

    @ExceptionHandler(UnauthorizedException.class)
    @ResponseBody
    public ResponseResult unauthorizedException(UnauthorizedException exception) {
        LOGGER.error(UnauthorizedException.class.getName(), exception);
        return ResponseResultFactory.authorityFail(exception.getMessage());
    }

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseBody
    public ResponseResult fieldException(HttpRequestMethodNotSupportedException exception) {
        LOGGER.error(ExceptionsHandler.class.getName(), exception);
        return ResponseResultFactory.exceptionFail("不支持"+exception.getMethod()+"请求");
    }


    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseResult allExceptionHandler(Exception exception, HttpServletRequest request) {
        LOGGER.error(exception.getMessage(), exception);
        return ResponseResultFactory.exceptionFail("服务器异常");
    }


  /*  private ReturnResult handlerException(ProceedingJoinPoint pjp, Throwable e) {
        ReturnResult result = new ReturnResult();

        // 已知异常【注意：已知异常不要打印堆栈，否则会干扰日志】
        // 校验出错，参数非法
        if (e instanceof FieldException || e instanceof IllegalArgumentException) {
            result.setMsg(e.getLocalizedMessage());
            result.setCode(ReturnResultCode.FAIL_FIELD.getCode());
        }
        // 没有登陆
        else if (e instanceof UnauthorizedException) {
            result.setMsg("认证失败");
            result.setCode(ReturnResultCode.FAIL_AUTHORITY.getCode());
        }
        // 没有权限
        else if (e instanceof OtherException) {
            result.setMsg("服务器异常");
            result.setCode(ReturnResultCode.FAIL_EXCEPTION.getCode());
        } else {
            logger.error(pjp.getSignature() + " error ", e);

            // TODO 未知的异常，应该格外注意，可以发送邮件通知等
            result.setMsg("服务器异常");
            result.setCode(ReturnResultCode.FAIL_EXCEPTION.getCode());
        }

        return result;
    }*/

/*
    @Autowired
    private SysLogErrorService sysLogErrorService;

    *//**
     * 处理自定义异常
     *//*
    @ExceptionHandler(RenException.class)
    public Result handleRenException(RenException ex){
        Result result = new Result();
        result.error(ex.getCode(), ex.getMsg());

        return result;
    }

    @ExceptionHandler(DuplicateKeyException.class)
    public Result handleDuplicateKeyException(DuplicateKeyException ex){
        Result result = new Result();
        result.error(ErrorCode.DB_RECORD_EXISTS);

        return result;
    }

    @ExceptionHandler(Exception.class)
    public Result handleException(Exception ex){
        logger.error(ex.getMessage(), ex);

        saveLog(ex);

        return new Result().error();
    }

    *//**
     * 保存异常日志
     *//*
    private void saveLog(Exception ex){
        SysLogErrorEntity log = new SysLogErrorEntity();

        //请求相关信息
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
        log.setIp(IpUtils.getIpAddr(request));
        log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
        log.setRequestUri(request.getRequestURI());
        log.setRequestMethod(request.getMethod());
        Map<String, String> params = HttpContextUtils.getParameterMap(request);
        if(MapUtil.isNotEmpty(params)){
            log.setRequestParams(JSON.toJSONString(params));
        }

        //异常信息
        log.setErrorInfo(ExceptionUtils.getErrorStackTrace(ex));

        //保存
        sysLogErrorService.save(log);
    }*/


   /* CREATE TABLE `sys_log_error` (
            `id` bigint(20) NOT NULL COMMENT 'id',
            `request_uri` varchar(200) DEFAULT NULL COMMENT '请求URI',
            `request_method` varchar(20) DEFAULT NULL COMMENT '请求方式',
            `request_params` text COMMENT '请求参数',
            `user_agent` varchar(500) DEFAULT NULL COMMENT '用户代理',
            `ip` varchar(32) DEFAULT NULL COMMENT '操作IP',
            `error_info` text COMMENT '异常信息',
            `creator` bigint(20) DEFAULT NULL COMMENT '创建者',
            `create_date` datetime DEFAULT NULL COMMENT '创建时间',
    PRIMARY KEY (`id`),
    KEY `idx_create_date` (`create_date`)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='异常日志';*/
}